package com.google.code.sip.ucenter.service.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.RootClassFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.code.sip.core.dao.mongo.GenericMongoDao;
import com.google.code.sip.core.dao.mongo.MongoFactoryBean;
import com.google.code.sip.core.dao.mongo.MongoHelper;
import com.google.code.sip.core.dao.mongo.MongoInfo;
import com.google.code.sip.ucenter.service.MongoManager;

@Service("mongoManager")
public class MongoManagerImpl implements MongoManager {
	@Autowired
	private MongoHelper mongoHelper;
	@Autowired
	private MongoFactoryBean mongoFactory;

	@Override
	public void upgrade() {
		mongoHelper.upgrade();
	}

	@Override
	public MongoInfo getMongoInfo() {
		return mongoHelper.getMongoInfo();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<String> validate() {
		ClassFilter classFilter = new RootClassFilter(GenericMongoDao.class);
		List<Class<?>> daoClasses = getClassFromPackageWithFilter(
				"com.google.code.sip.ucenter.dao.mongo", classFilter);
		List<String> errors = new ArrayList<String>();
		for (Class<?> daoClass : daoClasses) {
			try {
				GenericMongoDao dao = null;
				dao = (GenericMongoDao) daoClass.newInstance();
				dao.setMongoFactory(mongoFactory);
				errors.addAll(validateEntity(dao));
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return errors;
	}

	@SuppressWarnings( { "unchecked", "unused" })
	private <T> List<String> validateEntity(GenericMongoDao dao) {
		List<String> errors = new ArrayList<String>();
		Iterator<T> iter = dao.fetch().iterator();
		while (iter.hasNext()) {
			try {
				T t = iter.next();
			} catch (RuntimeException e) {
				errors.add(e.getMessage());
			}
		}
		return errors;
	}

	public static List<Class<?>> getClassFromPackageWithFilter(
			String packageName, ClassFilter filter) {
		List<Class<?>> results = new ArrayList<Class<?>>();
		// 将包名转换为路径名
		String packageDirName = packageName.replace('.', '/');
		// 通过路径获取URL
		Enumeration<URL> resources = null;
		try {
			resources = Thread.currentThread().getContextClassLoader()
					.getResources(packageDirName);
		} catch (IOException e) {
			return results;
		}
		// 遍历获取的URL
		while (resources.hasMoreElements()) {
			URL url = resources.nextElement();
			// 如果是jar包
			if ("jar".equals(url.getProtocol())) {
				JarFile jarFile = null;
				try {
					JarURLConnection conn = (JarURLConnection) url
							.openConnection();
					jarFile = conn.getJarFile();
				} catch (IOException e) {
					continue;
				}
				// 遍历jar包中的所有entry
				for (Enumeration<JarEntry> entries = jarFile.entries(); entries
						.hasMoreElements();) {
					JarEntry entry = entries.nextElement();
					String entryName = entry.getName();
					// 是以指定路径开始&&是class文件&&不是内部类
					if (entryName.startsWith(packageDirName)
							&& entryName.endsWith(".class")
							&& entryName.indexOf("$") == -1) {
						// 把路径转变为类名 us/vifix/a/Class.class - us.vifix.a.Class
						String className = entryName.replace('/', '.')
								.substring(0, entryName.length() - 6);
						try {
							Class<?> clazz = Class.forName(className);
							// 过滤器
							if (filter != null && filter.matches(clazz)) {
								results.add(Class.forName(className));
							}
						} catch (ClassNotFoundException e) {

						}
					}
				}
				// 如果是文件系统
			} else if ("file".equals(url.getProtocol())) {
				String filePath = null;
				try {
					filePath = URLDecoder.decode(url.getFile(), "UTF-8");
				} catch (UnsupportedEncodingException e) {
					continue;
				}
				// 获取根目录并迭代获取所有class
				File rootDirectory = new File(filePath);
				getClassFromDirectory(packageName, rootDirectory, filter,
						results);
			}
		}

		return results;
	}

	private static void getClassFromDirectory(String packageName,
			File directory, ClassFilter filter, List<Class<?>> results) {
		// 如果不存在或者不是目录就直接返回
		if (!directory.exists() || !directory.isDirectory())
			return;
		// 获取目录下文件列表 过滤规则为是目录或者是class文件并且不是内部类
		File[] files = directory.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return (pathname.isDirectory() || (pathname.getName().endsWith(
						".class") && pathname.getName().indexOf("$") == -1));
			}
		});
		// 遍历
		for (File file : files) {
			// 如果是目录 迭代
			if (file.isDirectory()) {
				getClassFromDirectory(packageName + "." + file.getName(), file,
						filter, results);
			} else {
				// 去掉末尾的.class 组装成className
				String className = packageName
						+ "."
						+ file.getName().substring(0,
								file.getName().length() - 6);
				try {
					Class<?> clazz = Class.forName(className);
					// 过滤器
					if (filter != null && filter.matches(clazz)) {
						results.add(Class.forName(className));
					}
				} catch (ClassNotFoundException e) {

				}
			}
		}
	}
}
